package cn.chiship.sdk.core.util;

import cn.chiship.sdk.core.base.BaseResult;
import cn.chiship.sdk.core.exception.ExceptionUtil;
import cn.chiship.sdk.core.exception.custom.BusinessException;
import cn.chiship.sdk.core.util.zxing.QrCodeUtil;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.*;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.encryption.*;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.Map;

/**
 * @author LiJian
 */
public class PdfUtil {

	private static final Logger LOGGER = LoggerFactory.getLogger(PdfUtil.class);

	public static final String PDF_TEMPLATE_FIELD_TYPE_TEXT = "text:";

	public static final String PDF_TEMPLATE_FIELD_TYPE_IMAGE = "image:";

	/**
	 * 生成PDF
	 * @param newPdfPath
	 * @param reportData
	 * @return 结果
	 */
	public static BaseResult generalPdfByTemplateInput(InputStream inputStream, String newPdfPath,
			Map<String, Object> reportData, Boolean isEncryption, String password) {
		try (OutputStream fos = new FileOutputStream(newPdfPath);) {
			byte[] bytes = generalPdfByTemplateInput(inputStream, reportData);

			fos.write(bytes);
			fos.flush();
			fos.close();
			if (isEncryption) {
				pdfEncryption(password, newPdfPath);
			}
			return BaseResult.ok();
		}
		catch (Exception e) {
			return ExceptionUtil.formatException(e);
		}
	}

	/**
	 * 生成PDF
	 * @param templatePath
	 * @param newPdfPath
	 * @param reportData
	 * @return 结果
	 */
	public static BaseResult generalPdfByTemplate(String templatePath, String newPdfPath,
			Map<String, Object> reportData, Boolean isEncryption, String password) throws FileNotFoundException {
		return generalPdfByTemplateInput(new FileInputStream(templatePath), newPdfPath, reportData, isEncryption,
				password);
	}

	public static byte[] generalPdfByTemplate(String templatePath, Map<String, Object> reportData)
			throws FileNotFoundException {
		return generalPdfByTemplateInput(new FileInputStream(templatePath), reportData);
	}

	public static byte[] generalPdfByTemplateInput(InputStream inputStream, Map<String, Object> reportData) {
		try {
			ByteArrayOutputStream output = new ByteArrayOutputStream();
			byte[] buffer = new byte[4096];
			int n = 0;
			while (-1 != (n = inputStream.read(buffer))) {
				output.write(buffer, 0, n);
			}
			return generalPdfByTemplateInput(output.toByteArray(), reportData);
		}
		catch (Exception e) {
			throw new BusinessException(e.getLocalizedMessage());
		}
	}

	public static byte[] generalPdfByTemplateInput(byte[] datas, Map<String, Object> reportData) {
		try {
			PdfReader reader = new PdfReader(datas);
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			PdfStamper stamper = new PdfStamper(reader, bos);
			BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
			ArrayList<BaseFont> fontList = new ArrayList<>();
			fontList.add(bf);
			AcroFields fields = stamper.getAcroFields();
			fields.setSubstitutionFonts(fontList);
			fillData(stamper, fields, reportData);
			stamper.setFormFlattening(true);
			stamper.close();
			return bos.toByteArray();
		}
		catch (Exception e) {
			LOGGER.error("发生异常", e);
			throw new BusinessException(e.getLocalizedMessage());
		}
	}

	/**
	 * 填充模板
	 * @param fields 填充区域
	 * @param data 填充数据
	 */
	public static void fillData(PdfStamper stamper, AcroFields fields, Map<String, Object> data)
			throws IOException, DocumentException {
		for (Map.Entry<String, Object> entry : data.entrySet()) {
			String key = entry.getKey();
			if (key.split(":").length == 2) {
				String[] keys = key.split(":");
				if ("image".equals(keys[0])) {
					byte[] value = (byte[]) entry.getValue();
					int pageNo = fields.getFieldPositions(keys[1]).get(0).page;
					com.itextpdf.text.Rectangle rectangle = fields.getFieldPositions(keys[1]).get(0).position;
					float x = rectangle.getLeft();
					float y = rectangle.getBottom();
					float width = rectangle.getWidth();
					float height = rectangle.getHeight();
					// 读图片
					com.itextpdf.text.Image image = com.itextpdf.text.Image.getInstance(value);
					// 获取操作的页面
					PdfContentByte pdfContentByte = stamper.getOverContent(pageNo);
					// 根据域的大小缩放图片
					image.scaleToFit(width, height);
					// 添加图片
					image.setAbsolutePosition(x, y);
					pdfContentByte.addImage(image);
				}
				else {
					String value = String.valueOf(data.get(key));
					// 为字段赋值,注意字段名称是区分大小写的
					fields.setField(keys[1], value);
				}
			}
			else {
				throw new DocumentException("map Key格式不正确");
			}
		}
	}

	/**
	 * PDF加密
	 * @param password
	 * @param filePath
	 * @throws Exception
	 */
	public static void pdfEncryption(String password, String filePath) throws Exception {
		PDDocument load = PDDocument.load(new File(filePath));
		AccessPermission permissions = new AccessPermission();
		permissions.setCanExtractContent(false);
		permissions.setCanModify(false);
		permissions.setCanAssembleDocument(true);
		StandardProtectionPolicy p = new StandardProtectionPolicy(password, password, permissions);
		SecurityHandler sh = new StandardSecurityHandler(p);
		sh.prepareDocumentForEncryption(load);
		PDEncryption encryptionOptions = new PDEncryption();
		encryptionOptions.setSecurityHandler(sh);
		load.setEncryptionDictionary(encryptionOptions);
		load.save(filePath);
	}

	public static void pdfToImage(byte[] bytes, OutputStream os) throws IOException {
		pdfToImage(bytes, os, 1);
	}

	public static void pdfToImage(byte[] bytes, OutputStream os, int page) throws IOException {
		if (page <= 0) {
			page = 1;
		}
		page -= 1;
		PDDocument doc = PDDocument.load(bytes);
		PDFRenderer renderer = new PDFRenderer(doc);
		int pageCount = doc.getNumberOfPages();
		if (page + 1 > pageCount) {
			throw new BusinessException("PDF资源最多只有" + pageCount + "页");
		}
		BufferedImage image = renderer.renderImageWithDPI(page, 196);
		ImageIO.write(image, "PNG", os);
		/*
		 * for (int i = 0; i < pageCount; i++) { BufferedImage image =
		 * renderer.renderImageWithDPI(i, 196); ImageIO.write(image, "PNG", os); }
		 */
	}

	public static void main(String[] args) {

		/*
		 * try { Map<String, Object> reportData = new HashMap<String, Object>();
		 * reportData.put(PDF_TEMPLATE_FIELD_TYPE_TEXT + "regionName", "山东");
		 * reportData.put(PDF_TEMPLATE_FIELD_TYPE_TEXT +
		 * "firstLetter",DateUtils.getTime()); reportData.put(PDF_TEMPLATE_FIELD_TYPE_TEXT
		 * + "adCode",DateUtils.getTime()); reportData.put(PDF_TEMPLATE_FIELD_TYPE_TEXT +
		 * "fullPingYin",DateUtils.getTime()); reportData.put(PDF_TEMPLATE_FIELD_TYPE_TEXT
		 * +
		 * "remrk","山东省（Shandong）是中国华东地区的一个沿海省份，简称鲁，省会济南。位于中国东部沿海北纬34°22.9′-38°24.01′，东经114°47.5′-122°42.3′之间，自北而南与河北、河南、安徽、江苏4省接壤。 [22]  山东东西长721.03千米，南北长437.28千米，全省陆域面积15.58万平方千米。 [7]  2021年山东省的常住人口为10169.99万人，比上年增加了17.24万人。"
		 * );
		 *
		 * reportData.put(PDF_TEMPLATE_FIELD_TYPE_IMAGE + "image",
		 * ImageUtil.getImgByteByUrl(
		 * "https://cdn-chiship.oss-cn-beijing.aliyuncs.com/default/testPdfImage.png"));
		 * reportData.put(PDF_TEMPLATE_FIELD_TYPE_TEXT + "fillDate",DateUtils.getTime());
		 *
		 * byte[] bytes = generalPdfByTemplateInput(FileUtil.downLoadToByte(
		 * "https://cdn-chiship.oss-cn-beijing.aliyuncs.com/default/pdfTemplate.pdf"),
		 * reportData); try (OutputStream fos = new FileOutputStream("d:/1.pdf");) {
		 * fos.write(bytes); fos.flush(); fos.close();
		 *
		 * } catch (Exception e) { } } catch (Exception e) { e.printStackTrace(); }
		 */

		/*
		 * String templatePath = "D:\\template\\template.pdf"; Map<String, Object>
		 * reportData = new HashMap<String, Object>();
		 * reportData.put(PDF_TEMPLATE_FIELD_TYPE_TEXT + "cardNumber", "11李磊");
		 * reportData.put(PDF_TEMPLATE_FIELD_TYPE_IMAGE + "qrcode",
		 * QrCodeCreateUtil.createQrCode("ce22222sss", 900));
		 *
		 * BaseResult baseResult = generalPdfByTemplate(new FileInputStream(templatePath),
		 * reportData, false, "123456"); if (baseResult.isSuccess()) { FileOutputStream
		 * fileOutputStream = new FileOutputStream("d:\\1.pdf");
		 * fileOutputStream.write((byte[]) baseResult.getData()); } baseResult =
		 * generalPdfByTemplate(new FileInputStream(templatePath), reportData, true,
		 * "123456789"); if (baseResult.isSuccess()) { FileOutputStream fileOutputStream =
		 * new FileOutputStream("d:\\2.pdf"); fileOutputStream.write((byte[])
		 * baseResult.getData()); }
		 */

		// PrintUtil.console(new File("d:\\result.pdf").setExecutable(true));

		/*
		 * try { String templatePath = "C:\\Users\\lijian\\Desktop\\share.pdf";
		 *
		 * byte[] bufferedImage =
		 * QrCodeCreateUtil.createQrCode("http://120.26.50.81/admin/h5/invite/" + 1111 +
		 * ".action", 900); Map<String, Object> reportData = new HashMap<>(2);
		 * reportData.put(PdfUtil.PDF_TEMPLATE_FIELD_TYPE_TEXT + "username", "昵称:lijian");
		 * reportData.put(PdfUtil.PDF_TEMPLATE_FIELD_TYPE_TEXT + "phone",
		 * "手机号:18363003321"); reportData.put(PdfUtil.PDF_TEMPLATE_FIELD_TYPE_IMAGE +
		 * "qrcode", bufferedImage);
		 *//*
			 * BaseResult baseResult = generalPdfByTemplate(templatePath,
			 * "C:\\Users\\lijian\\Desktop\\share1.pdf", reportData, false, "123456");
			 * PrintUtil.console(baseResult);
			 *//*
				 * byte[] bytes = generalPdfByTemplate(templatePath, reportData);
				 * FileOutputStream os = new
				 * FileOutputStream("C:\\\\Users\\\\lijian\\\\Desktop\\2.png");
				 * pdfToImage(bytes, os);
				 *
				 * } catch (Exception e) { e.printStackTrace(); }
				 */
		try {
			byte[] bufferedImage = QrCodeUtil.generateQrCode("39919199232", 900);
			InputStream inputStream = new ByteArrayInputStream(bufferedImage);
			BufferedImage image = ImageIO.read(inputStream);
			File outfile = new File("D:\\\\2.jpg");
			ImageIO.write(image, "jpg", outfile);
		}
		catch (IOException e) {
			e.printStackTrace();
		}

	}

}
